package com.youxin.chat.pay.utils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Enumeration;

public class RSAUtils {


    /**
     *
     * 载入公钥
     * @param publicKeyCer 公钥目录
     * @return
     * @throws FileNotFoundException
     * @throws CertificateException
     */
    public static PublicKey loadPublicKey(String publicKeyCer) throws FileNotFoundException, CertificateException {
        InputStream inStream = new FileInputStream(publicKeyCer);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
        PublicKey publicKey = cert.getPublicKey();
        return publicKey;
    }



    /**
     *  载入私钥
     * @param privateKeyPfx
     * @param password
     * @return
     * @throws Exception
     */
    public static PrivateKey loadPrivateKey(String privateKeyPfx, String password) throws Exception{
        // Create a keystore object
        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        char[] nPassword = (char[]) null;
        if ((password == null) || (password.trim().equals(""))) {
            nPassword = (char[]) null;
        }
        else {
            nPassword = password.toCharArray();
        }
        // Load the file into the keystore
        keyStore.load(new FileInputStream(privateKeyPfx), nPassword);
        String aliaesName = "";
        Enumeration enumer = keyStore.aliases();
        while (enumer.hasMoreElements()) {
            aliaesName = (String) enumer.nextElement();
            if (keyStore.isKeyEntry(aliaesName)){
                return (PrivateKey) (keyStore.getKey(aliaesName, nPassword));
            }
        }
        throw new Exception("没有找到匹配私钥:"+privateKeyPfx);

    }


    /**
     * 还原私钥
     *
     * @param keyBytes
     * @return
     */
    public static PrivateKey loadPrivateKey(String str) {
        byte[] keyBytes = Base64.decodeBase64(str);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
                keyBytes);
        try {
            KeyFactory factory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = factory
                    .generatePrivate(pkcs8EncodedKeySpec);
            return privateKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String loadPrivateKeyStr(String filePath, String password) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        char[] nPassword = (char[])null;
        if (password != null && !password.trim().equals("")) {
            nPassword = password.toCharArray();
        } else {
            nPassword = (char[])null;
        }

        keyStore.load(new FileInputStream(filePath), nPassword);
        String aliaesName = "";
        Enumeration enumer = keyStore.aliases();

        do {
            if (!enumer.hasMoreElements()) {
                throw new Exception("没有找到匹配私钥:" + filePath);
            }

            aliaesName = (String)enumer.nextElement();
        } while(!keyStore.isKeyEntry(aliaesName));

        PrivateKey privateKey = (PrivateKey)((PrivateKey)keyStore.getKey(aliaesName, nPassword));
        return java.util.Base64.getEncoder().encodeToString(privateKey.getEncoded());
    }

    public static String loadPubKeyStr(String filePath) throws Exception {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate cert = (X509Certificate)cf.generateCertificate(new FileInputStream(filePath));
        PublicKey publicKey = cert.getPublicKey();
        String publicKeyString = java.util.Base64.getEncoder().encodeToString(publicKey.getEncoded());
        return publicKeyString;
    }


    public static PublicKey loadPubKeyByStr(String str){
        byte[] encodedKey = Base64.decodeBase64(str);

        try {
            KeyFactory factory = KeyFactory.getInstance("RSA");
            PublicKey pubKey = factory.generatePublic(new X509EncodedKeySpec(encodedKey));

            return pubKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * RSA公钥加密
     * @param input
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static  byte[] encrypt(String data,PublicKey publicKey) throws Exception{
        Cipher cipher = null;
        cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey); // 用公钥pubKey初始化此Cipher
        return cipher.doFinal(data.getBytes());                 //加密
    }

    /**
     * RSA私钥解密
     * @param input
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String decrypt(byte[] input, PrivateKey privateKey)  throws Exception{
        Cipher cipher = null;
        cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey); // 用私钥priKey初始化此cipher
        return new String(cipher.doFinal(input));
    }

    public static byte[] doSignature(String content, PrivateKey priKey, String encode) throws Exception {
        Signature signature = Signature.getInstance("SHA1WithRSA");
        signature.initSign(priKey);
        signature.update(content.getBytes(encode));
        byte[] signed = signature.sign();
        return signed;
    }

    public static byte[] doSignature(byte[] content, PrivateKey priKey,String algorithm) throws Exception {
        Signature signature = Signature.getInstance(algorithm);
        signature.initSign(priKey);
        signature.update(content);
        byte[] signed = signature.sign();
        return signed;
    }

    public static byte[] doSignature256(String content, PrivateKey priKey, String encode) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(priKey);
        signature.update(content.getBytes(encode));
        byte[] signed = signature.sign();
        return signed;
    }

    /**
     * 验证SHA1WithRSA 签名信息
     * @param signature
     * @param plainText
     * @return
     * @throws Exception
     */
    public static  boolean verfySha1WithRsa(byte[] signature,byte[] plainText,PublicKey publicKey) throws Exception {
        return verfy(signature, plainText,"SHA1WithRSA",publicKey);
    }

    /**
     * 验证RSA签名信息（指定签名方法）
     * @param signature
     * @param plainText
     * @param signatureMethod
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static  boolean verfy(byte[] signature,byte[] plainText,String signatureMethod,PublicKey publicKey) throws Exception{
        Signature sig = Signature.getInstance(signatureMethod);
        sig.initVerify(publicKey);  // 用公钥初始化此用于Signature对象。
        sig.update(plainText);
        return sig.verify(signature);     //签名验证
    }
}
